#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "utils.h"
#include "lexer.h"

static struct kw *root = NULL;

void lexer_set_root(struct kw *_root)
{
	root = _root;
}

static struct kw *lexer_filter(struct kw *in, int in_fail, struct kw *name, int name_fail)
{
	if (name_fail != 0)
		return NULL;
	if (name != NULL)
		return name;
	if (in_fail != 0)
		return NULL;
	return in;
}

static struct kw *lexer_compare(struct lexer *lex, struct kw *kw, seg_t token)
{
   struct kw *in = NULL, *name = NULL;
	 int in_fail = 0, name_fail = 0;
		
   for (;kw != NULL; kw = kw_sib(kw)) {
		if (kw_is_input(kw)) {
			if (in != NULL)
				in_fail++;
			in = kw;
		} else if (kw_match(kw, lex->buf + start_seg(token), len_of_seg(token)) == 0) {
			if (name != NULL)
				name_fail++;
			name = kw;
		}
	}
	return lexer_filter(in, in_fail, name, name_fail);
}

static void lexer_set_kw(struct lexer *lex, seg_t seg, struct kw *kw)
{
	seg_point_t start = start_seg(seg);
	lex->kw_pool[start] = kw;
}

static struct kw *lexer_get_eol_back(struct lexer *lex)
{
	seg_t seg = seg_list_back(&lex->eol);
	if (valid_seg(seg))
		return lex->kw_pool[start_seg(seg)];
	else
		return NULL;
}


static void lexer_push_eol(struct lexer *lex, struct kw *accept)
{
	seg_t seg = seg_list_pop(&lex->free_kw);
	lexer_set_kw(lex, seg, accept);
	seg_list_push(&lex->eol, seg);
}

static int do_lexer(struct lexer *lex, struct kw *kw)
{
	if (token_size(&lex->token) == 0) {
		return 1;
	}
	seg_t token = token_pop_front(&lex->token);
	struct kw *accept = lexer_compare(lex, kw, token);
  if (accept == NULL) {
    return 0;
	}
	token_push(&lex->backup, token);
  lexer_push_eol(lex, accept);
  if (kw_is_input(accept)) 
	   seg_list_push(&lex->args, token);
	return do_lexer(lex, kw_son(accept));
}

static char token_tmp[TOKEN_MAX_SIZE];

const char *lexer_token_str(struct lexer *lex, seg_t token)
{
	if (valid_seg(token)) {
		seg_point_t start = start_seg(token);
		strncpy(token_tmp, lex->buf+start, len_of_seg(token) + 1);
	} else 
		token_tmp[0] = 0;
	return token_tmp;
}


static void error(struct lexer *lex)
{
	if (token_size(&lex->token) == 0)
		printf("\nIncomplete command, expect\n\n");
	else
		printf("\nError at '%s', expect\n\n", 
  lexer_token_str(lex,token_front(&lex->token)));
	
	if (seg_list_size(&lex->eol) == 0) {
		kw_show_sib(root);
	} else {
		struct kw *kw = lexer_get_eol_back(lex);
		kw_show_son(kw);
	}
}

static void lexer_son_table(struct lexer *lex)
{
	struct kw *kw = lexer_get_eol_back(lex);
	kw_show_son(kw);
}

static void lexer_own_table(struct lexer *lex)
{
	struct kw *kw = lexer_get_eol_back(lex);
	seg_t backup_token = token_back(&lex->backup);
	const char *s = lexer_token_str(lex, backup_token);
	
	if (kw_is_input(kw)) {
		printf("\n  %s\n", kw->word);
		return;
	} 
  int len = kw->size - strlen(s);
	if (len >= 0) {
		int ret = snprintf(lex->autofill, LEXER_AUTOFILL - 1, "%s ", kw->word + strlen(s));
		lex->autofill[ret] = 0;
	}
}

void init_lexer(struct lexer *lex, const char *buf, seg_t cmd)
{
	lex->buf = buf;
	lex->buf_size = strlen(buf);
	seg_list_init(&lex->eol);
  seg_list_init(&lex->args);
	seg_list_init(&lex->free_kw);
	lex->autofill[0]=0;
	seg_point_t i;
	for (i = 0; i < SEG_LIMIT; i++){
		seg_list_push(&lex->free_kw, make_seg(i, i + 1));
	}
  token_init(&lex->backup);
  tokenize(&lex->token, buf, lex->buf_size);
//  token_print(&lex->token, buf);
}

int lexer_execute(void *_l)
{
	struct lexer *lex = (struct lexer *)_l;
	if (!token_size(&lex->token)) {
		return 0;
	}
	if (!do_lexer(lex, root) || seg_list_size(&lex->eol) == 0) {
		error(lex);
		return 0;
	}
	struct kw *kw = lexer_get_eol_back(lex);
	if (!kw_executable(kw)) {
		error(lex);
		return 0;
	}
	kw_execute(kw, lex->buf, &lex->args);
	return 0;
}

int lexer_help(struct lexer *lex)
{
	if (!do_lexer(lex, root)){
    error(lex);
		return 0;
	}
	if (seg_list_size(&lex->eol) == 0 || token_size(&lex->backup) == 0) {
		kw_show_sib(root);
		return 0;
	}
	if (lex->token.last_white)
		lexer_son_table(lex);
	else 
		lexer_own_table(lex);
	return 0;
}




